# - Find ragel executable and provides macros to generate custom build rules
# The module defines the following variables:
#
#  RAGEL_EXECUTABLE - path to the ragel program
#  RAGEL_VERSION - version of ragel
#  RAGEL_FOUND - true if the program was found
#
# The minimum required version of ragel can be specified using the
# standard CMake syntax, e.g. find_package(RAGEL 2.1.3)
#
# If ragel is found, the module defines the macros:
#  RAGEL_TARGET(<Name> <RagelInput> <CodeOutput> [COMPILE_FLAGS <string>])
# which will create  a custom rule to generate  a parser. <RagelInput> is
# the path to  a ragel file. <CodeOutput> is the name  of the source file
# generated by ragel.  If  COMPILE_FLAGS  option is  specified,  the  next
# parameter is  added in the ragel  command line.  The macro defines a set 
# of variables:
#  RAGEL_${Name}_DEFINED - true is the macro ran successfully
#  RAGEL_${Name}_INPUT - The input source file, an alias for <RagelInput>
#  RAGEL_${Name}_OUTPUT_SOURCE - The source file generated by ragel
#  RAGEL_${Name}_OUTPUTS - The sources files generated by ragel
#  RAGEL_${Name}_COMPILE_FLAGS - Options used in the ragel command line
#
#  ====================================================================
#  Example:
#
#   find_package(RAGEL)
#   RAGEL_TARGET(MyParser parser.rl ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp)
#   add_executable(Foo main.cpp ${RAGEL_MyParser_OUTPUTS})
#  ====================================================================

#  ====================================================================
#  Copyright (C) 2014 MediaSift Ltd.
# 
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
# 
#  The above copyright notice and this permission notice shall be included in all
#  copies or substantial portions of the Software.
# 
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#  SOFTWARE.
#  ====================================================================

find_program(RAGEL_EXECUTABLE NAMES ragel DOC "path to the ragel executable")
mark_as_advanced(RAGEL_EXECUTABLE)

if(RAGEL_EXECUTABLE)
  # the ragel commands should be executed with the C locale, otherwise
  # the message (which are parsed) may be translated
  set(_Ragel_SAVED_LC_ALL "$ENV{LC_ALL}")
  set(ENV{LC_ALL} C)

  execute_process(COMMAND ${RAGEL_EXECUTABLE} --version
    OUTPUT_VARIABLE RAGEL_version_output
    ERROR_VARIABLE RAGEL_version_error
    RESULT_VARIABLE RAGEL_version_result
    OUTPUT_STRIP_TRAILING_WHITESPACE)

  set(ENV{LC_ALL} ${_Ragel_SAVED_LC_ALL})

  if(NOT ${RAGEL_version_result} EQUAL 0)
    message(SEND_ERROR "Command \"${RAGEL_EXECUTABLE} --version\" failed with output:\n${RAGEL_version_error}")
  else()
    # eg: Ragel State Machine Compiler version 6.8 Feb 2013
    string(REGEX REPLACE "^Ragel State Machine Compiler version ([0-9].[0-9])?.*" "\\1" 
    	RAGEL_VERSION "${RAGEL_version_output}")
  endif()

  # internal macro
  macro(RAGEL_TARGET_option_extraopts Options)
    set(RAGEL_TARGET_extraopts "${Options}")
    separate_arguments(RAGEL_TARGET_extraopts)
    list(APPEND RAGEL_TARGET_cmdopt ${RAGEL_TARGET_extraopts})
  endmacro()

  #============================================================
  # RAGEL_TARGET (public macro)
  #============================================================
  #
  macro(RAGEL_TARGET Name RagelInput RagelOutput)
    set(RAGEL_TARGET_output_header "")
    set(RAGEL_TARGET_cmdopt "")
    set(RAGEL_TARGET_outputs "${RagelOutput}")
    if(NOT ${ARGC} EQUAL 3 AND NOT ${ARGC} EQUAL 5)
      message(SEND_ERROR "Usage")
    else()
      # Parsing parameters
      if(${ARGC} EQUAL 5)
        if("${ARGV3}" STREQUAL "COMPILE_FLAGS")
          RAGEL_TARGET_option_extraopts("${ARGV4}")
        endif()
      endif()

      # Generate a fast goto driven FSM
      list(APPEND RAGEL_TARGET_cmdopt "-G2")

      add_custom_command(OUTPUT ${RAGEL_TARGET_outputs}
        ${RAGEL_TARGET_extraoutputs}
        COMMAND ${RAGEL_EXECUTABLE}
        ARGS ${RAGEL_TARGET_cmdopt} -o ${ARGV2} ${ARGV1}
        DEPENDS ${ARGV1}
        COMMENT "[RAGEL][${Name}] Building parser with ragel ${RAGEL_VERSION}"
        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

      # define target variables
      set(RAGEL_${Name}_DEFINED TRUE)
      set(RAGEL_${Name}_INPUT ${ARGV1})
      set(RAGEL_${Name}_OUTPUTS ${RAGEL_TARGET_outputs})
      set(RAGEL_${Name}_COMPILE_FLAGS ${RAGEL_TARGET_cmdopt})
      set(RAGEL_${Name}_OUTPUT_SOURCE "${RagelOutput}")

    endif()
  endmacro()
  #
  #============================================================

endif()

include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(RAGEL REQUIRED_VARS  RAGEL_EXECUTABLE
                                        VERSION_VAR RAGEL_VERSION)

# FindRAGEL.cmake ends here
